home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / gr2ps / RCS / gr2ps.c,v < prev   
Encoding:
Text File  |  1992-10-05  |  27.6 KB  |  1,206 lines

  1. head     1.4;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.4
  10. date     92.10.05.13.06.21;  author mgbaker;  state Exp;
  11. branches ;
  12. next     1.3;
  13.  
  14. 1.3
  15. date     91.10.27.00.49.28;  author eklee;  state Exp;
  16. branches ;
  17. next     1.2;
  18.  
  19. 1.2
  20. date     90.12.05.22.20.28;  author eklee;  state Exp;
  21. branches ;
  22. next     1.1;
  23.  
  24. 1.1
  25. date     90.12.05.22.19.50;  author eklee;  state Exp;
  26. branches ;
  27. next     ;
  28.  
  29.  
  30. desc
  31. @Initial distribution
  32. @
  33.  
  34.  
  35. 1.4
  36. log
  37. @Made it so we can handle buggy gremlin output in which the stated
  38. length of a text string (that is composed of digits) is wrong.
  39. @
  40. text
  41. @/*
  42.  *  gr2ps - convert a gremlin file into a PostScript printer
  43.  *  language file, which can be printed to printers which
  44.  *  support PostScript (like the Apple LaserWriter).
  45.  *
  46.  *  (c) 1986 John Coker
  47.  *  University of California, Berkeley
  48.  */
  49.  
  50. #include <stdio.h>
  51. #include <ctype.h>
  52. #include <math.h>
  53. #include <varargs.h>
  54.  
  55. #define isinteger(c)    (isdigit(c) || (c) == '-')
  56. #define isfloat(c)    (isdigit(c) || (c) == '.' || (c) == '-')
  57.  
  58. char    *program;
  59. char    USAGE[] = "usage: %s [ -n ] [ -R font ] [ -I font ] [ -B font ] [ -S font ] [ -s X Y ] [ -t X Y ] [ -p X Y ] [ -o file ] [ file ]\n";
  60. char    *errfile = NULL;
  61. int    errline = -1;
  62.  
  63. int    setscale = 0;
  64. double    gscaleX = 1.0, gscaleY = 1.0;
  65. int    settrans = 0;
  66. double    gtransX = 0.0, gtransY = 0.0;
  67. int    setplace = 0;
  68. double    gplaceX = 0.0, gplaceY = 0.0;
  69. int    newformat = 0;
  70.  
  71. char    *R_fontname = "Times-Roman";
  72. char    *I_fontname = "Times-Italic";
  73. char    *B_fontname = "Times-Bold";
  74. char    *S_fontname = "Courier-Bold";
  75.  
  76. main(argc, argv)
  77.     char    *argv[];
  78. {
  79.     extern char    *rindex();
  80.     extern double    atof();
  81.     register char    *ap;
  82.     char        *outputfile = NULL;
  83.     FILE        *input, *output;
  84.     int        status;
  85.  
  86.     program = rindex(*argv, '/');
  87.     if (program == NULL)
  88.         program = *argv;
  89.     else
  90.         program++;
  91.  
  92.     /* process command line options */
  93.     while (--argc > 0 && **++argv == '-') {
  94.         if (*(*argv+1) == '\0')
  95.             break;
  96.         for (ap = ++*argv; *ap != '\0'; ap++)
  97.             switch (*ap) {
  98.             case 'B':    /* bold font name */
  99.                 if (--argc < 1 || *++argv == NULL) {
  100.                     fprintf(stderr, USAGE, program);
  101.                     exit(1);
  102.                 }
  103.                 B_fontname = *argv;
  104.                 break;
  105.             case 'I':    /* italic font name */
  106.                 if (--argc < 1 || *++argv == NULL) {
  107.                     fprintf(stderr, USAGE, program);
  108.                     exit(1);
  109.                 }
  110.                 I_fontname = *argv;
  111.                 break;
  112.             case 'R':    /* roman font name */
  113.                 if (--argc < 1 || *++argv == NULL) {
  114.                     fprintf(stderr, USAGE, program);
  115.                     exit(1);
  116.                 }
  117.                 R_fontname = *argv;
  118.                 break;
  119.             case 'S':    /* special font name */
  120.                 if (--argc < 1 || *++argv == NULL) {
  121.                     fprintf(stderr, USAGE, program);
  122.                     exit(1);
  123.                 }
  124.                 S_fontname = *argv;
  125.                 break;
  126.             case 'n':    /* newer file format */
  127.                 newformat = 1;
  128.                 break;
  129.             case 'o':    /* specity output file */
  130.                 if (--argc < 1 || *++argv == NULL) {
  131.                     fprintf(stderr, USAGE, program);
  132.                     exit(1);
  133.                 }
  134.                 outputfile = *argv;
  135.                 break;
  136.             case 'p':    /* place at this position */
  137.                 if (argc < 3 || !isfloat(argv[1][0]) ||
  138.                     !isfloat(argv[2][0])) {
  139.                     fprintf(stderr, USAGE, program);
  140.                     exit(1);
  141.                 }
  142.                 gplaceX = atof(argv[1]);
  143.                 gplaceY = atof(argv[2]);
  144.                 argc -= 2;
  145.                 argv += 2;
  146.                 setplace = 1;
  147.                 break;
  148.             case 's':    /* specify global scale */
  149.                 if (argc < 3 || !isfloat(argv[1][0]) ||
  150.                     !isfloat(argv[2][0])) {
  151.                     fprintf(stderr, USAGE, program);
  152.                     exit(1);
  153.                 }
  154.                 gscaleX = atof(argv[1]);
  155.                 gscaleY = atof(argv[2]);
  156.                 argc -= 2;
  157.                 argv += 2;
  158.                 setscale = 1;
  159.                 break;
  160.             case 't':    /* specify global translation */
  161.                 if (argc < 3 || !isfloat(argv[1][0]) ||
  162.                     !isfloat(argv[2][0])) {
  163.                     fprintf(stderr, USAGE, program);
  164.                     exit(1);
  165.                 }
  166.                 gtransX = atof(argv[1]);
  167.                 gtransY = atof(argv[2]);
  168.                 argc -= 2;
  169.                 argv += 2;
  170.                 settrans = 1;
  171.                 break;
  172.             default:    /* bad option */
  173.                 fprintf(stderr, USAGE, program);
  174.                 exit(1);
  175.             }
  176.     }
  177.     if (settrans && setplace) {
  178.         fprintf(stderr, "%s: Only one of -t and -p, please.\n",
  179.             program);
  180.         exit(1);
  181.     }
  182.  
  183.     /* open output file */
  184.     if (outputfile == NULL || *outputfile == '\0') {
  185.         /* use standard output */
  186.         output = stdout;
  187.     } else if ((output = fopen(outputfile, "w")) == NULL) {
  188.         fprintf(stderr, "%s: Can't open output file ", program);
  189.         perror(outputfile);
  190.         exit(1);
  191.     }
  192.  
  193.     /* read and translate given gremlin files */
  194.     if (argc > 0) {
  195.         /* loop over argument file names */
  196.         status = 0;
  197.         while (argc-- > 0) {
  198.             if (**argv == '\0' || !strcmp(*argv, "-")) {
  199.                 /* read standard input at this point */
  200.                 errline = 0;
  201.                 errfile = "(stdin)";
  202.                 status += grn_to_ps(input, output) != 0;
  203.             } else if ((input = fopen(*argv, "r")) == NULL) {
  204.                 fprintf(stderr, "%s: Can't open ", program);
  205.                 perror(*argv);
  206.                 status++;
  207.             } else {
  208.                 errline = 0;
  209.                 errfile = *argv;
  210.                 status += grn_to_ps(input, output) != 0;
  211.                 fclose(input);
  212.             }
  213.             argv++;
  214.         }
  215.     } else {
  216.         /* process standard input */
  217.         errline = 0;
  218.         errfile = "(stdin)";
  219.         status = grn_to_ps(stdin, output) != 0;
  220.     }
  221.  
  222.     if (output != stdout)
  223.         fclose(output);
  224.  
  225.     exit(0);
  226. }
  227.  
  228. char    OLDFIRSTLINE[] = "gremlinfile\n";
  229. char    NEWFIRSTLINE[] = "sungremlinfile\n";
  230. int    LASTELEMENT = -1;
  231.  
  232. static char    *element_names[] = {
  233.     "BOTLEFT",        /* bottom left text - 0 */
  234.     "BOTRIGHT",        /* bottom right text - 1 */
  235.     "CENTCENT",        /* center text - 2 */
  236.     "VECTOR",        /* vector - 3 */
  237.     "ARC",            /* arc - 4 */
  238.     "CURVE",        /* curve - 5 */
  239.     "POLYGON",        /* polygon - 6 */
  240.     "CURVE BSPLINE",    /* b-spline - 7 */
  241.     "CURVE BEZIER",        /* bezier spline - 8 */
  242.     NULL,
  243.     "TOPLEFT",        /* top left text - 10 */
  244.     "TOPCENT",        /* top center text - 11 */
  245.     "TOPRIGHT",        /* top right text - 12 */
  246.     "CENTLEFT",        /* left center text - 13 */
  247.     "CENTRIGHT",        /* right center text - 14 */
  248.     "BOTCENT",        /* bottom center text - 15 */
  249. };
  250. static int    element_count = sizeof (element_names) / sizeof (char *);
  251.  
  252. struct point {
  253.     double        p_x,
  254.             p_y;
  255. };
  256.  
  257. struct element {
  258.     short        e_what;        /* what type of element */
  259.     short        e_ptcnt;    /* number of points */
  260.     struct point    *e_points;    /* list of points */
  261.     short        e_brush;    /* brush style */
  262.     short        e_size;        /* text size */
  263.     char        *e_text;    /* text string */
  264.     double        e_llx,        /* lower-left X */
  265.             e_lly,        /* lower-left Y */
  266.             e_urx,        /* upper-right X */
  267.             e_ury;        /* upper-right Y */
  268. };
  269.  
  270. #define MAXPOINTS    500    /* maximum points per element */
  271. #define MAXELEMENTS    5000    /* maximum elements per file */
  272.  
  273. #define TOP        1    /* top oriented text */
  274. #define BOTTOM        2    /* bottom oriented text */
  275. #define LEFT        3    /* left justified text */
  276. #define CENTER        4    /* centered text */
  277. #define RIGHT        5    /* right justified text */
  278.  
  279. #define LARGE    1000000        /* initial value for max/min pairs */
  280.  
  281. /* these should be local variables, but ... */
  282. static struct element    elt_list[MAXELEMENTS];
  283. static struct point    point_list[MAXPOINTS];
  284.  
  285. grn_to_ps(input, output)
  286.     FILE    *input, *output;
  287. {
  288.     extern double    atof();
  289.     extern char    *malloc(), *savestr();
  290.     char        lbuf[1024];
  291.     register char    *lp, *ep;
  292.     struct point    *point_end = point_list + MAXPOINTS;
  293.     struct point    *ptp, *ptend;
  294.     struct element    *elt_end = elt_list + MAXELEMENTS;
  295.     struct element    *elt, *elend;
  296.     register int    e, t, len;
  297.     double        llx, lly, urx, ury;
  298.  
  299.     /* check validity of this file */
  300.     if (fgets(lbuf, sizeof (lbuf), input) == NULL) {
  301.         error("Input file is empty!");
  302.         return (-1);
  303.     }
  304.     errline = 1;
  305.     if (strcmp(lbuf, NEWFIRSTLINE) == 0) {
  306.         /* this is new format, at least */
  307.         newformat = 1;
  308.     } else if (strcmp(lbuf, OLDFIRSTLINE) != 0) {
  309.         error("Input file not produced by gremlin!");
  310.         return (-1);
  311.     }
  312.  
  313.     /* get orientation/positioning line */
  314.     if (fgets(lbuf, sizeof (lbuf), input) == NULL) {
  315.         error("Input file is too short (missing orientation).");
  316.         return (-1);
  317.     }
  318.     errline++;
  319.  
  320.     /* initialize bounding box values */
  321.     llx = lly = LARGE;
  322.     urx = ury = -LARGE;
  323.  
  324.     /* look through file reading picture elements */
  325.     elt = elt_list;
  326.     while (fgets(lbuf, sizeof (lbuf), input) != NULL && elt < elt_end) {
  327.         errline++;
  328.         /* read in this element specification */
  329.         for (lp = lbuf; isspace(*lp); lp++)
  330.             ;
  331.         if (newformat && !isinteger(*lp)) {
  332.             for (ep = lp; *ep != '\0' && *ep != '\n'; ep++)
  333.                 ;
  334.             do
  335.                 *ep-- = '\0';
  336.             while (ep > lp && isspace(*ep));
  337.             if (ep <= lp) {
  338.                 error("Missing element name!");
  339.                 return (-1);
  340.             }
  341.             for (e = 0; e < element_count; e++)
  342.                 if (element_names[e] != NULL &&
  343.                     !strcmp(element_names[e], lp))
  344.                     break;
  345.             if (e >= element_count) {
  346.                 error("Unknown element type %s!", lp);
  347.                 return (1);
  348.             }
  349.             elt->e_what = e;
  350.         } else if (isinteger(*lp)) {
  351.             /* old style numeric element type */
  352.             elt->e_what = atoi(lbuf);
  353.         } else {
  354.             error("Bad format for element specification.");
  355.             return (-1);
  356.         }
  357.         if (elt->e_what == LASTELEMENT) {
  358.             /* this is the end-of-list marker */
  359.             break;
  360.         }
  361.  
  362.         /* read in associated point list */
  363.         ptend = point_list;
  364.         while (fgets(lbuf, sizeof (lbuf), input) != NULL &&
  365.                ptend < point_end) {
  366.             errline++;
  367.             /* read in this X and Y coordinate */
  368.             for (lp = lbuf; isspace(*lp); lp++)
  369.                 ;
  370.             if (newformat && *lp == '*')
  371.                 break;
  372.             if (!isfloat(*lp))
  373.                 goto badpoint;
  374.             ptend->p_x = atof(lp);
  375.             while (isfloat(*lp))
  376.                 lp++;
  377.             while (isspace(*lp))
  378.                 lp++;
  379.             if (!isfloat(*lp)) {
  380. badpoint:            error("Bad point specified, need X and Y.");
  381.                 return (-1);
  382.             }
  383.             ptend->p_y = atof(lp);
  384.             if (!newformat &&
  385.                 ptend->p_x < 0.0 && ptend->p_y < 0.0) {
  386.                 /* end of point list */
  387.                 break;
  388.             }
  389.             ptend++;
  390.         }
  391.         if (ptend >= point_end) {
  392.             error("Too many points, maximum is %d!", MAXPOINTS);
  393.             return (-1);
  394.         }
  395.  
  396.         /* read brush and size specification */
  397.         if (fgets(lbuf, sizeof (lbuf), input) == NULL) {
  398.             error("File too short (no brush/size entry)!");
  399.             return (-1);
  400.         }
  401.         errline++;
  402.         for (lp = lbuf; isspace(*lp); lp++)
  403.             ;
  404.         if (!isdigit(*lp)) {
  405.             error("Missing brush value for entry!");
  406.             return (-1);
  407.         }
  408.         elt->e_brush = atoi(lp);
  409.         while (isdigit(*lp))
  410.             lp++;
  411.         while (isspace(*lp))
  412.             lp++;
  413.         if (!isdigit(*lp)) {
  414.             error("Missing size value for entry!");
  415.             return (-1);
  416.         }
  417.         elt->e_size = atoi(lp);
  418.  
  419.         /* read count/text specification */
  420.         if (fgets(lbuf, sizeof (lbuf), input) == NULL) {
  421.             error("File too short (missing text entry)!");
  422.             return (-1);
  423.         }
  424.         errline++;
  425.         for (lp = lbuf; isspace(*lp); lp++)
  426.             ;
  427.         if (!isdigit(*lp)) {
  428.             error("Missing text length value in entry!");
  429.             return (-1);
  430.         }
  431.         len = atoi(lp);
  432.         if (len <= 0) {
  433.             /* no text string */
  434.             elt->e_text = NULL;
  435.         } else {
  436.             char    *text;
  437.  
  438.             while (isdigit(*lp))
  439.                 lp++;
  440.             while (isspace(*lp))
  441.                 lp++;
  442.             text = lp;
  443.             for (t = 0; t < len && *lp != '\n'; t++)
  444.                 lp++;
  445.             if (t < len) {
  446. #ifdef NOTDEF
  447.                 error("Text not as long as length given!");
  448. /*
  449.  * There's a bug in gremlin that sometimes gives a bogus text length if
  450.  * the text itself is a string of digits.  But nothing goes wrong if you
  451.  * ignore the given length here.
  452.  */
  453.                 return(1);
  454. #else
  455.                 error("Text not as long as length given, but this is probably okay");
  456. #endif /* NOTDEF */
  457.             }
  458.             *lp = '\0';
  459.             elt->e_text = savestr(text);
  460.         }
  461.  
  462.         /* add this picture element to list */
  463.         elt->e_ptcnt = ptend - point_list;
  464.         if (elt->e_ptcnt > 0) {
  465.             elt->e_points = (struct point *)
  466.                 malloc(elt->e_ptcnt * sizeof (struct point));
  467.             if (elt->e_points == NULL) {
  468.                 fprintf(stderr,
  469.                 "%s: Not enough memory to save %d points!\n",
  470.                     program, elt->e_ptcnt);
  471.                 return (-1);
  472.             }
  473.             bcopy((char *)point_list, (char *)elt->e_points,
  474.                 elt->e_ptcnt * sizeof (struct point));
  475.         }
  476.  
  477.         /* scale and translate the elements */
  478.         if (setscale)
  479.             scale(elt, gscaleX, gscaleY);
  480.         if (settrans)
  481.             translate(elt, gtransX, gtransY);
  482.  
  483.         /* save the bounding box information */
  484.         findbbox(elt);
  485.         if (elt->e_llx < llx)
  486.             llx = elt->e_llx;
  487.         if (elt->e_lly < lly)
  488.             lly = elt->e_lly;
  489.         if (elt->e_urx > urx)
  490.             urx = elt->e_urx;
  491.         if (elt->e_ury > ury)
  492.             ury = elt->e_ury;
  493.  
  494.         /* on to the next element ... */
  495.         elt++;
  496.     }
  497.     elend = elt;
  498.  
  499.     /* handle placing the figure */
  500.     if (setplace) {
  501.         double    dx, dy;
  502.  
  503.         dx = gplaceX - llx;
  504.         dy = gplaceY - lly;
  505.  
  506.         /* move the individual elements */
  507.         for (elt = elt_list; elt < elend; elt++)
  508.             translate(elt, dx, dy);
  509.  
  510.         /* update the entire bounding box */
  511.         llx += dx;
  512.         lly += dy;
  513.         urx += dx;
  514.         ury += dy;
  515.     }
  516.  
  517.     /* output the header comments */
  518.     fprintf(output, "%%!\n");
  519.     fprintf(output, "%%%%Title: %s\n", errfile);
  520.     fprintf(output, "%%%%Creator: %s (Gremlin to PostScript)\n", program);
  521.     fprintf(output, "%%%%BoundingBox: %lg %lg %lg %lg\n",
  522.         llx, lly, urx, ury);
  523.     fprintf(output, "%%%%DocumentFonts: %s %s %s %s\n",
  524.         R_fontname, I_fontname, B_fontname, S_fontname);
  525.     fprintf(output, "%%%%Pages: 1\n");
  526.     fprintf(output, "%%%%EndComments\n\n");
  527.  
  528.     /* output the prologue code */
  529.     fprintf(output, "gsave\n");
  530.     fprintf(output, "%%%%EndProlog\n");
  531.     
  532.     /* Output polygons first, text second and lines last to keep one
  533.        object from covering another as much as possible. */
  534.     for (elt = elt_list; elt < elend; elt++) {
  535.         /* handle this picture element now */
  536.         putc('\n', output);
  537.         switch (elt->e_what) {
  538.         case 6:        /* polygon */
  539.             if (elt->e_ptcnt < 3) {
  540.                 error("Need three or more points in polygon.");
  541.                 return (1);
  542.             }
  543.             polystyle(elt->e_brush, elt->e_size, output);
  544.             makepolygon(elt->e_ptcnt, elt->e_points, output,
  545.                     elt->e_brush, elt->e_size);
  546.             break;
  547.         }
  548.         if (elt->e_what > 15) {
  549.             error("Bad element type %d; ignored.", elt->e_what);
  550.         }
  551.     }
  552.     for (elt = elt_list; elt < elend; elt++) {
  553.         /* handle this picture element now */
  554.         putc('\n', output);
  555.         switch (elt->e_what) {
  556.         case 0:        /* bottom-left justified text */
  557.             textstyle(elt->e_brush, elt->e_size, output);
  558.             textpoint(elt->e_ptcnt, elt->e_points, output);
  559.             textadjust(elt->e_text, BOTTOM, LEFT, output);
  560.             break;
  561.         case 1:        /* bottom-right justified text */
  562.             textstyle(elt->e_brush, elt->e_size, output);
  563.             textpoint(elt->e_ptcnt, elt->e_points, output);
  564.             textadjust(elt->e_text, BOTTOM, RIGHT, output);
  565.             break;
  566.         case 2:        /* center justified text */
  567.             textstyle(elt->e_brush, elt->e_size, output);
  568.             textpoint(elt->e_ptcnt, elt->e_points, output);
  569.             textadjust(elt->e_text, CENTER, CENTER, output);
  570.             break;
  571.         case 10:    /* top-left justified text */
  572.             textstyle(elt->e_brush, elt->e_size, output);
  573.             textpoint(elt->e_ptcnt, elt->e_points, output);
  574.             textadjust(elt->e_text, TOP, LEFT, output);
  575.             break;
  576.         case 11:    /* top-center justified text */
  577.             textstyle(elt->e_brush, elt->e_size, output);
  578.             textpoint(elt->e_ptcnt, elt->e_points, output);
  579.             textadjust(elt->e_text, TOP, CENTER, output);
  580.             break;
  581.         case 12:    /* top-right justified text */
  582.             textstyle(elt->e_brush, elt->e_size, output);
  583.             textpoint(elt->e_ptcnt, elt->e_points, output);
  584.             textadjust(elt->e_text, TOP, RIGHT, output);
  585.             break;
  586.         case 13:    /* left-center justified text */
  587.             textstyle(elt->e_brush, elt->e_size, output);
  588.             textpoint(elt->e_ptcnt, elt->e_points, output);
  589.             textadjust(elt->e_text, CENTER, LEFT, output);
  590.             break;
  591.         case 14:    /* right-center justified text */
  592.             textstyle(elt->e_brush, elt->e_size, output);
  593.             textpoint(elt->e_ptcnt, elt->e_points, output);
  594.             textadjust(elt->e_text, CENTER, RIGHT, output);
  595.             break;
  596.         case 15:    /* bottom-center justified text */
  597.             textstyle(elt->e_brush, elt->e_size, output);
  598.             textpoint(elt->e_ptcnt, elt->e_points, output);
  599.             textadjust(elt->e_text, BOTTOM, CENTER, output);
  600.             break;
  601.         }
  602.         if (elt->e_what > 15) {
  603.             error("Bad element type %d; ignored.", elt->e_what);
  604.         }
  605.     }
  606.     for (elt = elt_list; elt < elend; elt++) {
  607.         /* handle this picture element now */
  608.         putc('\n', output);
  609.         switch (elt->e_what) {
  610.         case 3:        /* vector */
  611.             if (elt->e_ptcnt < 2) {
  612.                 error("Need at least two points in a vector.");
  613.                 break;
  614.             }
  615.             linestyle(elt->e_brush, elt->e_size, output);
  616.             ptp = point_list;
  617.             makevector(elt->e_ptcnt, elt->e_points, output);
  618.             break;
  619.         case 4:        /* arc */
  620.             if (elt->e_ptcnt < 2) {
  621.                 error("Need at least two points for an arc!");
  622.                 return (1);
  623.             }
  624.             linestyle(elt->e_brush, elt->e_size, output);
  625.             makearc(elt->e_ptcnt, elt->e_points, output);
  626.             break;
  627.         case 5:        /* curve */
  628.             if (elt->e_ptcnt < 3) {
  629.                 error("Need at least three points for curve.");
  630.                 return (1);
  631.             }
  632.             linestyle(elt->e_brush, elt->e_size, output);
  633.             makecurve(elt->e_ptcnt, elt->e_points, output);
  634.             break;
  635.         case 7:        /* b-spline curve */
  636.             if (elt->e_ptcnt < 2) {
  637.                 error(
  638.                         "Can't draw B-spline with fewer than two points.");
  639.                 return (1);
  640.             }
  641.             linestyle(elt->e_brush, elt->e_size, output);
  642.             makebspline(elt->e_ptcnt, elt->e_points, output);
  643.             break;
  644.         case 8:        /* bezier spline curve */
  645.             if (elt->e_ptcnt < 3) {
  646.                 error(
  647.                         "Can't draw Bezier with fewer than two points.");
  648.                 return (1);
  649.             }
  650.             linestyle(elt->e_brush, elt->e_size, output);
  651.             makebezier(elt->e_ptcnt, elt->e_points, output);
  652.             break;
  653.         }
  654.         if (elt->e_what > 15) {
  655.             error("Bad element type %d; ignored.", elt->e_what);
  656.         }
  657.     }
  658.  
  659.     /* terminate the page description with trailer */
  660.     fprintf(output, "\n%%%%Trailer\n");
  661.     fprintf(output, "grestore\n");
  662.  
  663.     return (0);
  664. }
  665.  
  666. findbbox(elt)
  667.     struct element    *elt;
  668. {
  669.     struct point    *ptp, *end;
  670.     double        minx, maxx, miny, maxy;
  671.  
  672.     /* initialize bounding box values */
  673.     minx = miny = LARGE;
  674.     maxx = maxy = -LARGE;
  675.  
  676.     end = elt->e_points + elt->e_ptcnt;
  677.     for (ptp = elt->e_points; ptp < end; ptp++) {
  678.         if (ptp->p_x < minx)
  679.             minx = ptp->p_x;
  680.         if (ptp->p_x > maxx)
  681.             maxx = ptp->p_x;
  682.         if (ptp->p_y < miny)
  683.             miny = ptp->p_y;
  684.         if (ptp->p_y > maxy)
  685.             maxy = ptp->p_y;
  686.     }
  687.  
  688.     /* make sure we have a reaonable bounding box */
  689.     if (minx > maxx || miny > maxy)
  690.         minx = maxx = miny = maxy = 0.0;
  691.  
  692.     /* set them in the element and return */
  693.     elt->e_llx = minx;
  694.     elt->e_lly = miny;
  695.     elt->e_urx = maxx;
  696.     elt->e_ury = maxy;
  697.     return (0);
  698. }
  699.  
  700. scale(elt, xscale, yscale)
  701.     struct element    *elt;
  702.     double    xscale, yscale;
  703. {
  704.     struct point    *ptp, *end;
  705.  
  706.     end = elt->e_points + elt->e_ptcnt;
  707.     for (ptp = elt->e_points; ptp < end; ptp++) {
  708.         ptp->p_x *= xscale;
  709.         ptp->p_y *= yscale;
  710.     }
  711.     /* find bounding box now that it's changed */
  712.     return findbbox(elt);
  713. }
  714.  
  715. translate(elt, xtrans, ytrans)
  716.     struct element    *elt;
  717.     double    xtrans, ytrans;
  718. {
  719.     struct point    *ptp, *end;
  720.  
  721.     end = elt->e_points + elt->e_ptcnt;
  722.     for (ptp = elt->e_points; ptp < end; ptp++) {
  723.         ptp->p_x += xtrans;
  724.         ptp->p_y += ytrans;
  725.     }
  726.  
  727.     /* adjust bounding box by translation */
  728.     elt->e_llx += xtrans;
  729.     elt->e_lly += ytrans;
  730.     elt->e_urx += xtrans;
  731.     elt->e_ury += ytrans;
  732.     return (0);
  733. }
  734.  
  735. double    curgray = 0.0;
  736. int    dashset = 0;
  737. double    curwidth = -1.0;
  738.  
  739. #define THINWIDTH    0.3
  740. #define MEDWIDTH    0.8
  741. #define THICKWIDTH    1.4
  742.  
  743. linestyle(brush, size, output)
  744.     FILE    *output;
  745. {
  746.     /* set up line style (or brush) approriately */
  747.     switch (brush) {
  748.     case 1:        /* thin dotted lines */
  749.         fputs("[1.0 1.6] 0 setdash\n", output);
  750.         dashset = 1;
  751.         if (curwidth != THINWIDTH) {
  752.             curwidth = THINWIDTH;
  753.             fprintf(output, "%lg setlinewidth\n", curwidth);
  754.         }
  755.         break;
  756.     case 2:        /* thin dot-dashed lines */
  757.         fputs("[1.0 1.6 3.5 1.6] 0 setdash ", output);
  758.         dashset = 1;
  759.         if (curwidth != THINWIDTH) {
  760.             curwidth = THINWIDTH;
  761.             fprintf(output, "%lg setlinewidth\n", curwidth);
  762.         }
  763.         break;
  764.     case 3:        /* thick solid lines */
  765.         if (dashset) {
  766.             fputs("[] 0 setdash ", output);
  767.             dashset = 0;
  768.         }
  769.         if (curwidth != THICKWIDTH) {
  770.             curwidth = THICKWIDTH;
  771.             fprintf(output, "%lg setlinewidth\n", curwidth);
  772.         }
  773.         break;
  774.     case 4:        /* thin dashed lines */
  775.         fputs("[3.5 3.0] 0 setdash ", output);
  776.         dashset = 1;
  777.         if (curwidth != THINWIDTH) {
  778.             curwidth = THINWIDTH;
  779.             fprintf(output, "%lg setlinewidth\n", curwidth);
  780.         }
  781.         break;
  782.     case 5:        /* thin solid lines */
  783.         if (dashset) {
  784.             fputs("[] 0 setdash ", output);
  785.             dashset = 0;
  786.         }
  787.         if (curwidth != THINWIDTH) {
  788.             curwidth = THINWIDTH;
  789.             fprintf(output, "%lg setlinewidth\n", curwidth);
  790.         }
  791.         break;
  792.     case 6:        /* medium solid lines */
  793.         if (dashset) {
  794.             fputs("[] 0 setdash ", output);
  795.             dashset = 0;
  796.         }
  797.         if (curwidth != MEDWIDTH) {
  798.             curwidth = MEDWIDTH;
  799.             fprintf(output, "%lg setlinewidth\n", curwidth);
  800.         }
  801.         break;
  802.     default:    /* bad brush type */
  803.         error("Bad brush type %d specified; ignored.", brush);
  804.         return (1);
  805.     }
  806.  
  807.     /* lines are always drawn full strength */
  808.     if (curgray != 0.0) {
  809.         curgray = 0.0;
  810.         fprintf(output, "%lg setgray\n", curgray);
  811.     }
  812.  
  813.     /* size is ignored for vectors, arcs and curves */
  814.  
  815.     return (0);
  816. }
  817.  
  818. #define BLACK    16
  819. #define WHITE    1
  820.  
  821. polystyle(brush, size, output)
  822.     FILE    *output;
  823. {
  824.     double    level, steps;
  825.  
  826.     /* ignore outline style (or brush) here */
  827.  
  828.     /* size is stipple pattern index */
  829.     if (size > BLACK)
  830.         size = BLACK;
  831.     if (size < WHITE)
  832.         size = WHITE;
  833.     steps = 100.0 / (double)BLACK;
  834.     level = 100.0 - (steps * (size - 1));
  835.     if (level != curgray) {
  836.         fprintf(output, "%lg setgray\n", level / 100.0);
  837.         curgray = level;
  838.     }
  839.  
  840.     return (0);
  841. }
  842.  
  843. textpoint(count, list, output)
  844.     struct point    *list;
  845.     FILE        *output;
  846. {
  847.     double        x, y;
  848.     register int    i;
  849.  
  850.     if (count < 1) {
  851.         error("Need at least one point for text items!");
  852.         return (-1);
  853.     }
  854. #ifdef STUPID
  855.     x = y = 0.0;
  856.     for (i = 0; i < count; i++) {
  857.         x += list[i].p_x;
  858.         y += list[i].p_y;
  859.     }
  860.     x = x / (double)count;
  861.     y = y / (double)count;
  862. #else !STUPID
  863.     x = list[0].p_x;
  864.     y = list[0].p_y;
  865. #endif STUPID
  866.     
  867.     fprintf(output, "%lg %lg moveto\n", x, y);
  868.     return(0);
  869. }
  870.  
  871. char    *curfont = NULL;
  872. int    cursize = -1;
  873.  
  874. textstyle(brush, size, output)
  875.     FILE    *output;
  876. {
  877.     char    *fname;
  878.     int    fsize;
  879.  
  880.     /* set the font face from brush */
  881.     switch (brush) {
  882.     default:    /* unknown face */
  883.         error("Bad font number %d in entry; using Roman.", brush);
  884.         /* fall through ... */
  885.     case 1:        /* roman */
  886.         fname = R_fontname;
  887.         break;
  888.     case 2:        /* italics */
  889.         fname = I_fontname;
  890.         break;
  891.     case 3:        /* bold */
  892.         fname = B_fontname;
  893.         break;
  894.     case 4:        /* special */
  895.         fname = S_fontname;
  896.         break;
  897.     }
  898.  
  899.     /* set point size from the size entry */
  900.     switch (size) {
  901.     case 1:        /* 8 point */
  902.         fsize = 8;
  903.         break;
  904.     case 2:        /* 12 point */
  905.         fsize = 12;
  906.         break;
  907.     case 3:        /* 18 point */
  908.         fsize = 18;
  909.         break;
  910.     case 4:        /* 28 point */
  911.         fsize = 28;
  912.         break;
  913.     default:
  914.         error("Bad font size %d; using eight point.", size);
  915.         fsize = 8;
  916.         break;
  917.     }
  918.  
  919.     /* text is always printed full strength */
  920.     if (curgray != 0.0) {
  921.         fputs("0 setgray\n", output);
  922.         curgray = 0.0;
  923.     }
  924.  
  925.     /* get font at given size if not already done */
  926.     if (fname != curfont || fsize != cursize) {
  927.         fprintf(output,
  928.             "/%s findfont %d scalefont setfont\n", fname, fsize);
  929.         curfont = fname;
  930.         cursize = fsize;
  931.     }
  932.  
  933.     return (0);
  934. }
  935.  
  936. textadjust(text, vert, hor, output)
  937.     char    *text;
  938.     FILE    *output;
  939. {
  940.     char        sbuf[BUFSIZ], *send = sbuf + sizeof (sbuf) - 1;
  941.     register char    *tp, *sp;
  942.     double        vmove;
  943.  
  944.     if (text == NULL || *text == '\0') {
  945.         error("Null text string to show!");
  946.         return (-1);
  947.     }
  948.     tp = text;
  949.     sp = sbuf;
  950.     while (*tp != '\0' && sp < send) {
  951.         switch (*tp) {
  952.         case '(':
  953.         case ')':
  954.         case '\\':
  955.             *sp++ = '\\';
  956.             *sp++ = *tp++;
  957.             break;
  958.         default:
  959.             *sp++ = *tp++;
  960.             break;
  961.         }
  962.     }
  963.     *sp = '\0';
  964.  
  965.     /* make adjustment movements, we try to do this optimally ... */
  966.     switch (vert) {
  967.     case BOTTOM:
  968.         vmove = 1.0;
  969.         break;
  970.     case CENTER:
  971.         vmove = 1.0 - (double)cursize / 2.0;
  972.         break;
  973.     case TOP:
  974.         vmove = 1.0 - (double)cursize;
  975.         break;
  976.     }
  977.  
  978.     switch (hor) {
  979.     case LEFT:
  980.         if (vmove != 0.0)
  981.             fprintf(output, "0 %lg rmoveto ", vmove);
  982.         fprintf(output, "(%s) show\n", sbuf);
  983.         break;
  984.     case CENTER:
  985.         fprintf(output,
  986.         "(%s) dup stringwidth pop 2.0 div -1 mul %lg rmoveto show\n",
  987.             sbuf, vmove);
  988.         break;
  989.     case RIGHT:
  990.         fprintf(output,
  991.             "(%s) dup stringwidth pop -1 mul %lg rmoveto show\n",
  992.             sbuf, vmove);
  993.         break;
  994.     }
  995.  
  996.     return (0);
  997. }
  998.  
  999. makevector(count, list, output)
  1000.     struct point    *list;
  1001.     FILE        *output;
  1002. {
  1003.     struct point    *ptp, *ptend;
  1004.  
  1005.     if (list == NULL || count < 2)
  1006.         return (1);
  1007.  
  1008.     ptend = list + count;
  1009.     ptp = list;
  1010.  
  1011.     fprintf(output, "newpath\n    %lg %lg moveto\n",
  1012.         ptp->p_x, ptp->p_y);
  1013.     for (++ptp; ptp < ptend; ptp++)
  1014.         fprintf(output, "    %lg %lg lineto\n",
  1015.             ptp->p_x, ptp->p_y);
  1016.     fputs("stroke\n", output);
  1017.  
  1018.     return (0);
  1019. }
  1020.  
  1021. makepolygon(count, list, output, brush, size)
  1022.     struct point    *list;
  1023.     FILE        *output;
  1024. {
  1025.     struct point    *ptp, *ptend;
  1026.  
  1027.     if (list == NULL || count < 3)
  1028.         return (1);
  1029.  
  1030.     ptp = list;
  1031.     ptend = list + count;
  1032.  
  1033.     /* output the filled region now */
  1034.     fprintf(output, "newpath\n    %lg %lg moveto\n",
  1035.         ptp->p_x, ptp->p_y);
  1036.     for (++ptp; ptp < ptend; ptp++) {
  1037.         fprintf(output, "    %lg %lg lineto\n",
  1038.             ptp->p_x, ptp->p_y);
  1039.     }
  1040.     fputs("closepath fill\n", output);
  1041.  
  1042.     /* draw the outline now, unless brush is zero */
  1043.     if (brush > 0) {
  1044.         linestyle(brush, size, output);
  1045.         ptp = list;
  1046.         fprintf(output, "newpath\n    %lg %lg moveto\n",
  1047.             ptp->p_x, ptp->p_y);
  1048.         for (++ptp; ptp < ptend; ptp++)
  1049.             fprintf(output, "    %lg %lg lineto\n",
  1050.                 ptp->p_x, ptp->p_y);
  1051.         fputs("closepath stroke\n", output);
  1052.     }
  1053.  
  1054.     return (0);
  1055. }
  1056.  
  1057. #define sqr(x)    ((x) * (x))
  1058. #define TWOPI    (2.0 * 3.1415927)
  1059.  
  1060. makearc(count, list, output)
  1061.     struct point    *list;
  1062.     FILE        *output;
  1063. {
  1064.     double    ang1, ang2, radius;
  1065.     double    dx, dy;
  1066.  
  1067.     /* get radius from center of curvature and a point */
  1068.     radius = hypot(list[0].p_x - list[1].p_x, list[0].p_y - list[1].p_y);
  1069.  
  1070.     fputs("newpath ", output);
  1071.     if (count == 2 || count == 6 ||
  1072.         (list[1].p_x == list[2].p_x && list[1].p_y == list[2].p_y)) {
  1073.         /* drawing a circle, don't need angles */
  1074.         fprintf(output, "%lg %lg %lg 0 360 arc",
  1075.             list[0].p_x, list[0].p_y, radius);
  1076.     } else {
  1077.         /* drawing an arc, find two angles */
  1078.                 dx = list[1].p_x - list[0].p_x;
  1079.                 dy = list[1].p_y - list[0].p_y;
  1080.                 ang1 = atan2(dy, dx) / TWOPI * 360.0;
  1081.                 dx = list[2].p_x - list[0].p_x;
  1082.                 dy = list[2].p_y - list[0].p_y;
  1083.                 ang2 = atan2(dy, dx) / TWOPI * 360.0;
  1084.         /* output proper PostScript code */
  1085.         fprintf(output, "%lg %lg %lg %lg %lg arc",
  1086.             list[0].p_x, list[0].p_y, radius, ang1, ang2);
  1087.     }
  1088.     fputs(" stroke\n", output);
  1089.  
  1090.     return (0);
  1091. }
  1092.  
  1093. error(va_alist)
  1094.     va_dcl
  1095. {
  1096.     char *format;
  1097.     va_list args;
  1098.  
  1099.     va_start(args);
  1100.     format = va_arg(args, char *);
  1101.  
  1102.     fprintf(stderr, "%s: \"%s\", %d: ", program, errfile, errline);
  1103.     vfprintf(stderr, format, args);
  1104.     putc('\n', stderr);
  1105. }
  1106.  
  1107. char *
  1108. savestr(str)
  1109.     char    *str;
  1110. {
  1111.     extern char    *malloc();
  1112.     char        *ptr;
  1113.     int        len;
  1114.  
  1115.     if (*str == NULL || (len = strlen(str)) < 1)
  1116.         return (NULL);
  1117.     if ((ptr = malloc(len + 1)) == NULL) {
  1118.         fprintf(stderr, "%s: Not enough memory for %d char. string!\n",
  1119.             program, len);
  1120.         exit(1);
  1121.     }
  1122.     strcpy(ptr, str);
  1123.     return (ptr);
  1124. }
  1125. @
  1126.  
  1127.  
  1128. 1.3
  1129. log
  1130. @Used to exit if grn file contained a single point vector (now only ignores).
  1131. @
  1132. text
  1133. @d406 1
  1134. d408 5
  1135. d414 3
  1136. @
  1137.  
  1138.  
  1139. 1.2
  1140. log
  1141. @Shaded objects used to obscure lines and text.
  1142. @
  1143. text
  1144. @d564 1
  1145. a564 1
  1146.                 return (1);
  1147. @
  1148.  
  1149.  
  1150. 1.1
  1151. log
  1152. @Initial revision
  1153. @
  1154. text
  1155. @d483 2
  1156. a484 1
  1157.     /* output all the elements into the file */
  1158. d489 18
  1159. d522 39
  1160. a585 9
  1161.         case 6:        /* polygon */
  1162.             if (elt->e_ptcnt < 3) {
  1163.                 error("Need three or more points in polygon.");
  1164.                 return (1);
  1165.             }
  1166.             polystyle(elt->e_brush, elt->e_size, output);
  1167.             makepolygon(elt->e_ptcnt, elt->e_points, output,
  1168.                     elt->e_brush, elt->e_size);
  1169.             break;
  1170. d604 2
  1171. a605 31
  1172.         case 10:    /* top-left justified text */
  1173.             textstyle(elt->e_brush, elt->e_size, output);
  1174.             textpoint(elt->e_ptcnt, elt->e_points, output);
  1175.             textadjust(elt->e_text, TOP, LEFT, output);
  1176.             break;
  1177.         case 11:    /* top-center justified text */
  1178.             textstyle(elt->e_brush, elt->e_size, output);
  1179.             textpoint(elt->e_ptcnt, elt->e_points, output);
  1180.             textadjust(elt->e_text, TOP, CENTER, output);
  1181.             break;
  1182.         case 12:    /* top-right justified text */
  1183.             textstyle(elt->e_brush, elt->e_size, output);
  1184.             textpoint(elt->e_ptcnt, elt->e_points, output);
  1185.             textadjust(elt->e_text, TOP, RIGHT, output);
  1186.             break;
  1187.         case 13:    /* left-center justified text */
  1188.             textstyle(elt->e_brush, elt->e_size, output);
  1189.             textpoint(elt->e_ptcnt, elt->e_points, output);
  1190.             textadjust(elt->e_text, CENTER, LEFT, output);
  1191.             break;
  1192.         case 14:    /* right-center justified text */
  1193.             textstyle(elt->e_brush, elt->e_size, output);
  1194.             textpoint(elt->e_ptcnt, elt->e_points, output);
  1195.             textadjust(elt->e_text, CENTER, RIGHT, output);
  1196.             break;
  1197.         case 15:    /* bottom-center justified text */
  1198.             textstyle(elt->e_brush, elt->e_size, output);
  1199.             textpoint(elt->e_ptcnt, elt->e_points, output);
  1200.             textadjust(elt->e_text, BOTTOM, CENTER, output);
  1201.             break;
  1202.         default:    /* unknonw type */
  1203. a606 1
  1204.             break;
  1205. @
  1206.